#ifndef xpack_utils_private_memory_flow
#define xpack_utils_private_memory_flow
#pragma push_macro("xuser") 
#undef  xuser
#define xuser mixc::utils_private_memory_flow::inc
#include"configure/platform.hpp"
#include"concurrency/lock/atom_fetch_add.hpp"
#include"concurrency/lock/atom_fetch_and.hpp"
#include"concurrency/lock/atom_fetch_or.hpp"
#include"concurrency/lock/atom_fetch_sub.hpp"
#include"concurrency/lock/atom_fetch_xor.hpp"
#include"concurrency/lock/atom_load.hpp"
#include"concurrency/lock/atom_sub.hpp"
#include"concurrency/lock/atom_swap.hpp"
#include"concurrency/lock/atom_store.hpp"
#include"concurrency/thread.hpp"
#include"concurrency/thread_self.hpp"
#include"define/base_type.hpp"
#include"instruction/bit_test.hpp"
#include"instruction/bit_test_and_reset.hpp"
#include"instruction/bit_test_and_set.hpp"
#include"macro/xdebug+.hpp"
#include"macro/xdefer.hpp"
#include"macro/xexport.hpp"
#include"macro/xinit.hpp"
#include"macro/xmodify.hpp"
#include"macro/xnew.hpp"
#include"macro/xunlikely.hpp"
#include"memop/cast.hpp"
#include"utils/bits_indicator.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_private_memory_flow::origin{
    struct memory_flow;
}

namespace mixc::utils_private_memory_flow{
    typedef struct node{
        node      * prev;
        node      * next;

        #if xis_os32
    private:
        uxx         paddingx[2];
        #endif
    } * nodep;

    typedef struct node_free{
        node_free * next;
        uxx         bytes;

        #if xis_os32
    private:
        uxx         paddingx[2];
        #endif
    } * node_freep;

    typedef struct node_plus : node{
        // 当前块长度（单位为 size_one）是多少
        uxx         blocks;

        // 该参数用于对齐
        uxx         padding;

        #if xis_os32
    private:
        uxx         paddingx[2];
        #endif
    } * node_plusp;

    enum : uxx{
        // 每层 64 个级别
        scale                   = 64,

        // 小块以 scale_one 为区分单位
        // 无论是大块还是小块，scale_one 都是分配的最小单位
        scale_one               = sizeof(node),

        // 大块以 scale_two 为区分单位
        scale_two               = scale_one * scale,

        // 块数不超过该值定义为小块，否为定义为大块
        boundary                = scale,

        // 每次从底层分配器中获取一个页来管理，每一个页都是按 page_bytes 对齐
        page_bytes              = scale_two * scale,

        // 页对齐大小
        page_align_size         = page_bytes,

        // 用于获取页内偏移
        mask_to_get_offset      = page_bytes - 1,

        // 用于获取页首地址
        mask_to_get_header      = ~mask_to_get_offset,

        // 页首部位指示器位数
        max_bits                = page_bytes / scale_one,

        // 跳过检查的次数
        // 从其他线程推送过来的释放请求
        max_skip_times          = 8,

        wait_change_owners      = 1 << 0,
        mask_to_get_self_id     = ~(wait_change_owners),
        i_new_push              = 1,
        new_push                = 1 << i_new_push,
    };

    using indicator_t = inc::bits_indicator<scale>;

    struct meta_token;
    struct page_header;
    struct base_info{
        uxx             m_i_enter{};
        uxx             m_i_exit{};
        node_free       m_head{};
        node_free     * m_tail = & m_head;
        meta_token    * m_owner{};
        uxx             m_used_bytes{};
        uxx             m_active_object_count{};
        uxx             m_async_returned{};
    };

    inline inc::thread      g_mem_thread;
    inline meta_token     * g_back;

    struct meta_token : private base_info{
        meta_token(meta_token * owner){
            // 使用原子存储，确保缓存对其他 cpu 可见
            inc::atom_store(xmodify(m_owner), owner);
        }

        /**
         * @brief 
         * 更改分配所有权
         * @note 约定该函数只被分配器所有线程调用
         * @param back_owner 新的所有者
         */
        void raise_change_ownership(meta_token * back_owner) {
            for(auto current = 
                inc::atom_fetch_or(xmodify(m_i_enter), 1);;        // 设置 bit0 表示进入分配器将进入交接态
                inc::thread_self::yield()){

                // 如果 m_i_exit != current，就表示有其他异步归还内存的线程还停留在
                // void push_async(voidp mem, uxx bytes) 的部分2
                // 需要这些线程都执行完
                // inc::atom_fetch_add(xmodify(m_i_exit), 2); 才行
                if (inc::atom_load(xmodify(m_i_exit)) == current){
                    inc::atom_store(xmodify(m_owner), back_owner); // 先设置 owner
                    g_mem_thread.resume();

                    // 如果当前队列不为空
                    // 就将当前队列和 back_owner 队列拼接起来
                    if (xmodify(m_head) != m_tail) {
                        auto prev       = inc::atom_swap(xmodify(back_owner->m_tail), m_tail);
                        inc::atom_store(xmodify(prev->next), m_head.next);
                    }

                    inc::atom_fetch_xor(xmodify(m_i_enter), 1);    // 后清除 i_enter bit0，交接完成
                    break;
                }
            }
        }

        /**
         * @brief 
         * 异步释放内存，从其他线程归还内存
         * @note 约定该函数被其他非本分配器所有线程调用
         * @param mem 释放的内存，要求大小是 struct node 的整数倍
         * @param bytes 释放内存的大小
         */
        void push_async(voidp mem, uxx bytes){
            uxx current             = {};

            // 部分1：
            // 先让 m_i_enter 计数，如果 current bit0 为 1 就表示当前分配器的所有者线程正在退出
            // 需要等待 raise_change_ownership 完成交接
            for(current = inc::atom_fetch_add(xmodify(m_i_enter), 2); 
                current & 1;
                current = inc::atom_load(xmodify(m_i_enter))){
                inc::thread_self::yield();
            }

            // 部分2：
            // 走到这后边的逻辑，如果所有者线程准备执行 raise_change_ownership 
            // 那得等到后边的逻辑执行完成
            // 如果原先所有者线程本身已经析构了
            // 那么重新加载 m_owner 就好了
            auto token              = inc::atom_load(xmodify(m_owner));

            if (token->push_async_core(mem, bytes) == 128 and token == g_back){
                g_mem_thread.resume();
            }
            inc::atom_fetch_add(xmodify(m_i_exit), 2);
        }

        uxx push_async_core(voidp mem, uxx bytes) {
            // 部分1：
            auto self               = node_freep(mem);
            auto prev               = node_freep(nullptr);
            inc::atom_store(xmodify(self->next), nullptr);
            inc::atom_store(xmodify(self->bytes), bytes);

            // 部分2：
            // m_tail 默认是指向 m_head 空节点的
            // 新 push 的节点 self 不断的替换 tail 的位置，并让被替换下来的 m_tail 指向自己
            // 这样就构成了 head -> self0 -> self1 -> ... -> selfn
            // 这样类似队列的结构
            prev                    = inc::atom_swap(xmodify(m_tail), self);

            // 部分3：
            inc::atom_store(xmodify(prev->next), self);
            return inc::atom_fetch_add(xmodify(m_async_returned), 1);
        }

        void alloc_counting(uxx bytes){
            m_active_object_count  += 1;
            m_used_bytes           += bytes;
        }

        void free_counting(uxx bytes, uxx count = 1){
            m_active_object_count  -= count;
            m_used_bytes           -= bytes;
        }

        /**
         * @brief 
         * 分配器所有者处理其他线程归还的内存
         * @tparam free_t void(void * ptr, uxx bytes)
         * @param all_returned 是否处于所有内存都归还的情况
         * @param free 释放内存回调
         */
        template<class free_t>
        void handler_async_returned(bool all_returned, free_t && free){
            // 先读取 head
            auto curr               = inc::atom_load(xmodify(m_head.next));
            auto next               = node_freep{};
            auto bytes              = uxx{};
            auto count              = uxx{};

            if (curr == nullptr){
                return;
            }

            while(true){
                // 如果下一个节点为 nullptr
                // 那么当前节点就暂时不释放了，并到此结束
                // 因为其他推送线程可能即将执行
                // uxx push_async_core(voidp mem, uxx bytes) 的部分3处的代码，让 next 指向下一个节点
                // 这里不等待它完成，所以直接到此打止
                if (next = inc::atom_load(xmodify(curr->next)); next == nullptr){
                    inc::atom_store(xmodify(m_head.next), curr);
                    break;
                }

                bytes               = inc::atom_load(xmodify(curr->bytes));
                free(curr, bytes);
                curr                = next;
                count              += 1;
            }

            // 如果所有内存都已经归还了，就不需要考虑 push_async_core 的问题了
            if (all_returned){
                bytes               = inc::atom_load(xmodify(curr->bytes));
                free(curr, bytes);
            }
            else{
                inc::atom_fetch_sub(xmodify(m_async_returned), count);
            }
        }

        template<class free_t>
        void handler_async_returned(free_t && free){
            this->handler_async_returned(false, free);
        }

        uxx alive_object(){
            return m_active_object_count;
        }

        uxx alloced_bytes(){
            return m_used_bytes;
        }

        bool is_all_returned(){
            auto async_returned     = inc::atom_load(xmodify(m_async_returned));
            auto active_object      = m_active_object_count;
            auto all_returned       = async_returned == active_object;
            return all_returned;
        }

    public:
        uxx             pages{};
        uxx             skip_count{};
        indicator_t     slot{};
        indicator_t     slot_plus{};
        page_header   * page_list{};
        node          * free_list_array[scale];
        node          * free_list_array_plus[scale];
    };

    typedef struct page_header{
    private:
        struct pair{ nodep begin = nullptr; uxx length = 0; };

        // 位图：
        // 每 1bit 标记 scale_one 字节数的内存在当前大页（一个大页占 page_bytes 字节）中是否被占用
        // 但也有不一样的地方，比如标记块 0 至块 3 这段连续的空间被占用
        // 实际只要给 bmp 的第 0bit 和第 3bit 置位即可
        // 该位图主要用作查询相邻的块是否空闲，如果空闲则指示可以合并
        u08             bmp[max_bits / 8] = {0};
    public:
        page_header   * prev{};
        page_header   * next{};
        meta_token    * token{};
        uxx             dummy{};

        page_header(meta_token * token);

        /**
         * @brief 
         * 当前块在大页中的块下标
         * @param node 当前块
         * @return uxx 块下标
         */
        uxx index_of(nodep node){
            return node - nodep(this + 1);
        }

        /**
         * @brief 
         * 获取当前块左相邻块的空闲块数
         * @param current 当前块
         * @return pair 左相邻块空闲信息
         */
        pair left_free_block_of(nodep current){
            if (uxx index = index_of(current); get(index - 1)){
                return pair{};
            }
            else if (get(index - 2)){
                return pair{ current - 1, 1 };
            }
            else{
                auto plus = node_plusp(current) - 1;
                auto blocks = plus->blocks;
                return pair{ current - blocks, blocks };
            }
        }

        /**
         * @brief 
         * 获取当前块的右相邻块的空闲块数
         * @param current 当前块
         * @param length 当前块的长度
         * @return pair 右相邻块空闲信息
         */
        pair right_free_block_of(nodep current, uxx length){
            if (uxx index = index_of(current += length); get(index)){
                return {};
            }
            else if (get(index + 1)){
                return { current, 1 };
            }
            else{
                return { current, node_plusp(current)->blocks };
            }
        }

        /**
         * @brief 
         * 获取当前大页第一个块的首地址
         */
        nodep first_block(){
            return nodep(this + 1);
        }

        /**
         * @brief 
         * 将当前块标记为空闲，并在块的首尾设置块长度信息
         * @param current 当前块
         * @param length 当前块的长度
         */
        void set_free_block_info(nodep current, uxx length){
            if (length <= 1){
                return;
            }

            // 在块的首尾设置长度信息，这样相邻块在释放时如果看到当前块是空闲的
            // 就可以得到当前块的长度，并计算出新的块长和首地址
            auto end        = node_plusp(nodep(current + length)) - 1;
            auto head       = node_plusp(current);
            head->blocks    = length;
            end->blocks     = length;
        }

        void mark_in_use(nodep current, uxx length){
            uxx index = index_of(current);
            set(index);
            set(index + length - 1);
        }

        void mark_free(nodep current, uxx length){
            uxx index = index_of(current);
            reset(index);
            reset(index + length - 1);
        }

        bool is_valid_in_use_block(nodep ptr, uxx bytes){
            auto i_expect           = (bytes - 1) / scale_one;
            auto free_blocks        = (i_expect + 1);

            // 如果当前位没有置位，要么当前块没有分配过，要么已经释放过了
            if (auto i = this->index_of(ptr); not this->get(i)){
                // TODO:do some logging...
                return false;
            }
            // 说明 bytes 值不对
            else if (i += free_blocks - 1; not this->get(i)){
                // TODO:do some logging...
                return false;
            }
            else{
                return true;
            }
        }

    private:
        /**
         * @brief 
         * 用于获取相邻的块是否被占用
         * @param index 块在大页中的下标
         * @return true 该下标对应的块处于[使用状态]
         * @return false 该下标对应的块处于[空闲状态]
         */
        bool get(uxx index){
            index += 1;
            return inc::bit_test(bmp[index >> 3], index & 0x7);
        }

        // 标记占用
        void set(uxx index){
            index += 1;
            inc::bit_test_and_set(xmodify(bmp[index >> 3]), index & 0x7);
        }

        // 标记空闲
        void reset(uxx index){
            index += 1;
            inc::bit_test_and_reset(xmodify(bmp[index >> 3]), index & 0x7);
        }
    } * page_headerp;

    enum : uxx{
        // 一个页一共有多少可用块
        blocks_per_page         = (page_bytes - sizeof(page_header)) / scale_one,
    };

    inline page_header::page_header(meta_token * token){
        inc::atom_store(xmodify(this->token), token);

        // 设置哨兵位
        set(uxx(-1));
        set(blocks_per_page);
    }

    // 必须是 2 的次幂
    static_assert((page_bytes & (page_bytes - 1)) == 0);
}

namespace mixc::utils_private_memory_flow::origin{
    struct memory_flow{
    private:
        meta_token * m_token;

        friend void mem_execute();
    public:
        friend meta_token;
        friend page_header;

        ~memory_flow(){
            // 没使用过动态内存分配
            if (m_token == nullptr) {
                return;
            }

            // 如果所有的内存都归还了，直接挨个释放就好了
            if (auto all_returned = 
                m_token->is_all_returned(); all_returned){
                m_token->handler_async_returned(all_returned, [this](voidp ptr, uxx bytes){
                    this->free_core(ptr, bytes);
                });

                // free_core 如果释放完所有列表了后会自动释放 m_token
            }
            // 否则需要转交分配器所有权
            else{
                m_token->raise_change_ownership(g_back);
            }
        }

        /**
         * @brief 
         * 当前分配器用了多少内存
         */
        uxx used_bytes() {
            return m_token ? m_token->alloced_bytes() : 0;
        }

        /**
         * @brief 
         * 当前分配器还有多少存活的对象
         */
        uxx alive_object() {
            return m_token ? m_token->alive_object() : 0;
        }

        /**
         * @brief 
         * 内存分配
         * @param bytes 期望的字节数
         * @return voidp 
         */
        voidp alloc(uxx bytes){
            xdebug_fail(bytes == 0){
                return nullptr;
            }

            // 注意：=============================================================================
            // 需要使用 xnew 通过构造函数初始化
            // 由于 memory_flow 是以 thread_local 变量的方式存在全局
            // 如果在它构造前有其他全局变量在初始化时调用 memory_flow::alloc 可能出现未定义行为
            xunlikely(m_token == nullptr){
                m_token             = (meta_token *)inc::memory::malloc(sizeof(meta_token));
                m_token             = (xnew(m_token) meta_token(m_token));
            }

            auto i_expect           = (bytes - 1) / scale_one;

            // 超出管理范畴
            if (i_expect >= blocks_per_page){
                return inc::memory::malloc_aligned((i_expect + 1) * scale_one, scale_one);
            }

            // 只对 memory_flow 管理的内存计数
            m_token->alloc_counting(bytes);

            // 惰性处理其他线程归还的内存
            // 比如内存是从当前线程的分配器分配的，但最终是由其他线程释放的
            this->async_pop_lazily();

            // slot 中置位位表示空闲的块
            // 选择最接近但不小于所需大小的块
            if (i_expect < boundary){
                if (auto i_closest = m_token->slot.index_of_first_set(i_expect); i_closest != not_exist){
                    return take_out(i_closest, i_expect, m_token->slot, m_token->free_list_array);
                }
            }
            if (i_expect < blocks_per_page){
                if (auto i_closest = m_token->slot_plus.index_of_first_set(i_expect / boundary); i_closest != not_exist){
                    return take_out(i_closest, i_expect, m_token->slot_plus, m_token->free_list_array_plus);
                }
            }
            return origin_alloc(i_expect);
        }

        /**
         * @brief 
         * 释放内存
         * @note bytes 必须大于 0
         * @param ptr 待归还内存的地址
         * @param bytes 归还内存的大小
         */
        void free(voidp ptr, uxx bytes){
            xdebug_fail(bytes == 0){
                return;
            }

            auto i_expect           = (bytes - 1) / scale_one; 

            // 超出管理的大小
            if (i_expect >= blocks_per_page){
                inc::memory::mfree_aligned(ptr);
                return;
            }

            auto current            = nodep(ptr);
            auto head               = get_page_header_by(current);
            auto o_token            = head->token;

            // 处理其他线程归还的内存：
            // 如果 o_token 指向 this->m_token
            // 表明本线程还活着，此操作是当前线程自己回收内存
            // 也就一定没有发生所有者转换，自然也就无需通过原子操作加载
            if (m_token == o_token) {
                this->async_pop_lazily();
                this->free_core(ptr, bytes);
                return;
            }
            else{
                o_token->push_async(ptr, bytes);
            }
        }

        /**
         * @brief 
         * 惰性处理其他线程归还的内存
         */
        void handle_async_memory_event(){
            if (m_token == nullptr) {
                return;
            }
            this->async_pop_lazily();
        }

    private:
        void free_core(voidp ptr, uxx bytes){
            auto current            = (nodep)ptr;
            auto head               = (get_page_header_by(current));

            if (not head->is_valid_in_use_block(current, bytes)){
                return;
            }

            auto i_expect           = (bytes - 1) / scale_one;
            auto free_block         = (current);
            auto free_size          = (i_expect + 1);
            auto left               = (head->left_free_block_of(current));
            auto right              = (head->right_free_block_of(current, free_size));

            // 只对 memory_flow 管理的内存计数
            // 如果当前释放块左边相邻的块空闲，就合并一下，并以左边空闲块的首地址作为新的首地址
            if (m_token->free_counting(bytes),
                head->mark_free(current, i_expect + 1); left.begin != nullptr){
                head->mark_free(left.begin, left.length);
                free_block          = left.begin;
                free_size          += left.length;
                remove(left.begin, left.length);
            }

            // 如果当前释放块右边相邻的块空闲，也合并一下
            if (right.begin != nullptr){
                free_size          += right.length;
                head->mark_free(right.begin, right.length);
                remove(right.begin, right.length);
            }

            // 整个页都空闲时就释放该页
            if (free_size == blocks_per_page){
                origin_free(head);
            }
            // 否则合成的更大的空闲块放回对应的链表数组中
            else{
                append(free_block, free_size);
            }
        }

        void async_pop_lazily(){
            // 忽略一定次数后就响应一下
            // 尽可能减少无效的原子操作
            if (m_token->skip_count += 1; m_token->skip_count == max_skip_times){
                m_token->skip_count   = 0;
                m_token->handler_async_returned([this](voidp ptr, uxx bytes){
                    this->free_core(ptr, bytes);
                });
            }
        }

        /**
         * @brief 
         * 从系统接口中分配大页，并拆分成两部分，一部分分配，剩余的返回空闲链表
         * @param i_expect 期望的块数 - 1
         * @return voidp 可用的内存
         */
        voidp origin_alloc(uxx i_expect){
            auto meta               = inc::memory::malloc_aligned(page_bytes, page_align_size);
            auto page               = xnew(meta) page_header(m_token);
            auto first              = page->first_block();

            inc::atom_fetch_add(xmodify(m_token->pages), 1);

            if (m_token->page_list == nullptr){
                m_token->page_list  = page;
                page->next          = page->prev = page;
            }
            else{
                auto head           = m_token->page_list;
                auto prev           = head->prev;
                prev->next          = page;
                page->prev          = head->prev;
                head->prev          = page;
                page->next          = head;
            }
            return split(first, blocks_per_page, i_expect);
        }

        /**
         * @brief 
         * 释放大页
         * @param page 大页首地址
         */
        void origin_free(page_header * page){
            auto next               = page->next;
            auto prev               = page->prev;

            inc::atom_fetch_sub(xmodify(m_token->pages), 1);

            if (page->~page_header(), inc::memory::mfree_aligned(page); next == page){
                m_token->~meta_token();
                inc::memory::mfree(m_token);
                inc::atom_store(xmodify(m_token), nullptr);
                return;
            }
            if (page == m_token->page_list){
                m_token->page_list  = next;
            }

            next->prev              = prev;
            prev->next              = next;
        }

        /**
         * @brief 
         * 从对应的链表数组中取出最接近的内存分配，并把剩余的部分放回
         * @param i_closest free_list[i_closest] 是最接近并满足需求的空闲链表
         * @param i_expect 期望的块数 - 1
         * @param slot 当前空闲链表数组的位图，每一个 bit 分别表示 free_list[bit_n] 是否有空闲内存
         * @param free_list 空闲链表数组
         * @return voidp 
         */
        voidp take_out(uxx i_closest, uxx i_expect, indicator_t & slot, node ** free_list){
            auto    first               = free_list[i_closest];
            auto    next                = first->next;

            // 若当前元素时该链表中最后一个元素，则将该位置的 slot 设置为空
            if (next == first){
                slot.reset(i_closest);
            }
            // 否则让下一个元素顶替 first 的位置
            else{
                next->prev              = first->prev;
                first->prev->next       = next;
                free_list[i_closest]    = next;
            }

            if (free_list == m_token->free_list_array){
                return split(first, i_closest + 1, i_expect);
            }
            else{
                return split(first, node_plusp(first)->blocks, i_expect);
            }
        }

        /**
         * @brief 
         * 拆分现有内存块，返回可用块，并放回剩余块
         * @param current 待拆分的块
         * @param total_blocks 总块数
         * @param i_expect 期望分配的块数 - 1
         * @return voidp 可用块首地址
         */
        voidp split(nodep current, uxx total_blocks, uxx i_expect){
            auto require_blocks         = i_expect + 1;

            if (get_page_header_by(current)->mark_in_use(current, require_blocks);
                total_blocks > require_blocks){
                auto rest               = current + require_blocks;
                auto rest_blocks        = total_blocks - require_blocks;
                xdebug(im_utils_memory_flow_split, current, rest, total_blocks, require_blocks, rest_blocks);
                xdebug_fail(rest_blocks > total_blocks);
                append(rest, rest_blocks);
            }
            return current;
        }

        /**
         * @brief 
         * 放回剩余块
         * @param rest 剩余块
         * @param rest_blocks 剩余块长度
         */
        void append(node * rest, uxx rest_blocks){
            auto i_rest_blocks = rest_blocks - 1;

            // 对于 scale_one
            if (get_page_header_by(rest)->set_free_block_info(rest, rest_blocks); i_rest_blocks < boundary){
                append(rest, i_rest_blocks, m_token->slot, m_token->free_list_array);
            }
            // 对于 scale_two
            // i_rest_blocks / boundary - 1，这里减一表示：
            // 可用字节数在 [scale_two * 1, scale_two * 2) 范围的内存放在空闲链表下标 0 处
            // 可用字节数在 [scale_two * 2, scale_two * 3) 范围的内存放在空闲链表下标 1 处
            // 以此类推
            // 
            // 比如期望分配 1024B 内存，而 scale_two 空闲链表数组下标 0 存放着 1120B 内存和 1032B 内存
            // 由于 1120B 排在前面，就会先分配
            // scale_two 空闲链表数组在对应的下标能找到不小于期望块数的空闲内存，但不一定是最接近期望大小的
            // 它混合了最佳匹配和首次匹配的特点，这个和 scale_one 的最佳匹配有点区别
            else {
                append(rest, i_rest_blocks / boundary - 1, m_token->slot_plus, m_token->free_list_array_plus);
            }
        }

        /**
         * @brief 
         * 放回剩余块
         * @param block 剩余块
         * @param index 需要放回 free_list_array[index] 链表中
         * @param slot 第 n 位表示 free_list_array[n] 存在可用内存
         * @param free_list_array 空闲链表数组
         */
        void append(node * block, uxx index, indicator_t & slot, node ** free_list_array){
            xdebug(im_utils_memory_flow_append, index, slot.get(index));

            // 是第一个元素，就作为首元
            if (slot.get(index) == 0){
                slot.set(index);
                free_list_array[index]  = block;
                block->next             = block;
                block->prev             = block;
            }
            // 新增的元素
            else{
                auto header             = free_list_array[index];
                block->prev             = header->prev;
                block->next             = header;
                header->prev->next      = block;
                header->prev            = block;
            }
        }

        /**
         * @brief 
         * 从空闲链表数组中移除元素
         * @param block 待移除的块
         * @param block_size 待移除块的长度
         */
        void remove(node * block, uxx block_size){
            if (auto i_blocks = block_size - 1; i_blocks < boundary){
                remove(block, i_blocks, m_token->slot, m_token->free_list_array);
            }
            else{
                remove(block, i_blocks / boundary - 1, m_token->slot_plus, m_token->free_list_array_plus);
            }
        }

        /**
         * @brief 
         * 从空闲链表数组中移除元素
         * @param block 待移除的块
         * @param index 待移除块在链表数组的下标
         * @param slot 第 n 位表示 free_list[n] 存在可用内存
         * @param free_list_array 空闲链表数组
         */
        void remove(nodep block, uxx index, indicator_t & slot, node ** free_list_array){
            auto next                   = block->next;
            auto prev                   = block->prev;
            xdebug(im_utils_memory_flow_remove, block, next, index);

            if (next == block){
                slot.reset(index);
                return;
            }
            if (block == free_list_array[index]){
                free_list_array[index]  = next;
            }

            next->prev                  = prev;
            prev->next                  = next;
        }

        static page_header * get_page_header_by(voidp ptr){
            // 因为在 ptr 块都是来自 64KB 地址对齐的页，所以可以通过屏蔽低 16bit 来得到页首地址
            auto begin                  = uxx(ptr) & mask_to_get_header;
            return (page_header *)begin;
        }
    };

    inline void mem_execute(){
        while(true){
            inc::thread_self::suspend(64);
            g_back->handler_async_returned([](voidp ptr, uxx bytes){
                auto   page     = memory_flow::get_page_header_by(ptr);
                auto   token    = inc::atom_load(xmodify(page->token));
                auto & mem      = inc::cast<memory_flow>(token);
                mem.free_core(ptr, bytes);
            });
        }
    }

    xinit(inc::the_mem){
        static meta_token info{ & info };
        inc::atom_store(xmodify(g_back), & info);

        g_mem_thread = inc::thread(xdetached{
            mem_execute();
        });
    };
}

#endif

xexport_space(mixc::utils_private_memory_flow::origin)
